/**
 * XXX: Document.
 * 
 * @author Jorge Hernandez
 */
class org.molamil.acto.props.TypeParser {
	
	
	// Properties
	
	public static function get NUMBER_CHARS():Array {
		return ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "."];
	}
	
	public static function get NUMBER_HEX_CHARS():Array {
		return ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"];
	}
	
	public static function get TYPE_PARSERS():Array {
		return [parseDate, parseNumber, parseBoolean];
	}
	
	
	// Functions
	
	public static function parse(value:String):Object {
		
		if (isNull(value))
			return null;
		
		// Execute all parsers in order.
		for (var i:Number = 0; i < TYPE_PARSERS.length; i++) {
			var parser:Function = TYPE_PARSERS[i];
			var o:Object = parser(value);
			if (o != null)
				return o;
		}
		
		return value;
	
	}
	
	//TODO: Add hex and octal and 001 numbers.
	public static function parseNumber(value:String):Number {
		var o:Number = null;
		if (isNumber(value)) {
			var n:Number = parseFloat(value);
			if (n != NaN)
				o = n;
		}
		return o;
	}
	
	public static function parseBoolean(value:String):Boolean {
		var o:Boolean = null;
		if (value.toLowerCase() == "true") {
			o = true;
		} else if (value.toLowerCase() == "false") {
			o = false;
		}
		return o;
	}
	
	public static function parseDate(value:String):Date {
		
		//TODO: Make it fully ISO 8601 compliant. 
	 	// YYYY-MM-DD hh:mm:ss
	 	
	 	var date:Date = null;
	 	
	 	if (isDate(value)) {
	 		
			var parts:Array = value.split(" ");
			var datePart:String = parts[0];
			var timePart:String = parts[1];
			var dateParts:Array = datePart.split("-");
			var timeParts:Array = timePart.split(":");
			
			date = new Date(dateParts[0], dateParts[1] - 1, dateParts[2], 
							timeParts[0], timeParts[1], timeParts[2]);
							
	 	}
								 
		return date;
		
	}
	
	public static function isNull(value:String):Boolean {
		return value == null || value == "";
	}
	
	//TODO: Add hex and octal.
	public static function isNumber(value:String):Boolean {
		
		if (isNull(value))
			return false;
			
		var b:Boolean = true;		var isE:Boolean = false;
		var numberChars:Array = NUMBER_CHARS;
		
		for (var i:Number = 0; i < value.length; i++) {
			
			var char:String = value.charAt(i);
			
			if (char.toLowerCase() == "-") {
				if (i == 0 && value.length > 1) {
					continue;
				} else {
					b = false;
					break;
				}
			}
			
			if (char.toLowerCase() == "e") {
				if (!isE && i != 0 && value.length > i + 1) {
					isE = true;
					continue;
				} else {
					b = false;
					break;
				}
			}
			
			if (char.toLowerCase() == "x") {
				if (i == 1 && value.charAt(0) == "0" && value.length > 2) {
					numberChars = NUMBER_HEX_CHARS;
					continue;
				} else {
					b = false;
					break;
				}
			}
			
			var isValidChar:Boolean = false;
			for (var j:Number = 0; j < numberChars.length; j++) {
				if (char == numberChars[j]) {
					isValidChar = true;
					break;
				}
			}
			if (!isValidChar) {
				b = false;
				break;
			}
			
		}
		
		return b;
		
	}
	
	//FIXME: Review, make more strict.
	public static function isDate(value:String):Boolean {
		
		if (isNull(value))
			return false;
		
		var parts:Array = value.split(" ");
		var datePart:String = parts[0];
		var timePart:String = parts[1];
		var dateParts:Array = datePart.split("-");
		var timeParts:Array = timePart.split(":");
		
		if (dateParts.length < 2)
			return false;
		
		for (var i:Number = 0; i < dateParts.length; i++) {
			if (dateParts[i] == null || !isNumber(dateParts[i]))
				return false;	
		}
		
		for (var i:Number = 0; i < timeParts.length; i++) {
			if (timeParts[i] == null || !isNumber(timeParts[i]))
				return false;	
		}

		return true;
		
	}
	
	
}